package Sonnet;

import java.awt.Dimension;

import javafx.application.Application;

import javafx.application.Platform;
import javafx.scene.*;
import javafx.scene.Scene;
import javafx.stage.Stage;

import javafx.fxml.FXMLLoader;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.scene.SnapshotParameters;

import java.awt.*;
import java.awt.image.*;
//import java.awt.event.ActionEvent;
import java.awt.Dimension;
import java.lang.Object;
import java.io.InputStream;
import java.io.File;
import javax.imageio.ImageIO;//Keep For .png Image Creation
import java.io.IOException;
import java.nio.ByteBuffer;

import javafx.scene.paint.Color;
import javafx.geometry.Rectangle2D;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.image.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.image.WritableImage.*;
import javafx.scene.input.KeyEvent;
//import javafx.scene.layout.VBox;
import javafx.scene.text.*;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.scene.layout.*;
//import javafx.scene.paint.Color;
//import javafx.scene.shape.*;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

//import java.util.Timer;
//import java.util.TimerTask;
import javax.swing.JFileChooser;
//import javafx.stage.DirectoryChooser;
//import javafx.stage.FileChooser;
import javafx.embed.swing.SwingFXUtils;
//import org.openqa.selenium.By;
//import org.openqa.selenium.WebDriver;
//import org.openqa.selenium.firefox.FirefoxDriver;

//import com.sun.tools.javac.api.JavacTaskPool.Worker;

//import org.apache.commons.io.FileUtils;

//import org.openqa.selenium.OutputType;

//import org.openqa.selenium.TakesScreenshot;


import org.jcodec.api.awt.SequenceEncoder;//Keep For .mp4 Video Creation

public class Sonnet extends Application
{

	@Override
	public void start(Stage stage) throws IOException
	{
		Thread thread = new Thread(() -> {
			try { Thread.sleep(400); }
			catch (InterruptedException exc) { throw new Error("Unexpected interruption", exc); }
			// Update text on FX Application Thread:
			Platform.runLater(new Runnable() {
				@Override
				public void run()
				{
					try { RainbowSystem(stage); }
					catch(IOException ie) { ie.printStackTrace(); }
				}
			});
		});
		thread.setDaemon(true);
		thread.start();
	}

	static void RainbowSystem(Stage primaryStage) throws IOException
	{
		primaryStage.setTitle("Sonnet");
		primaryStage.setWidth(1920);
		primaryStage.setHeight(1080);

		// This is how you know how much screen you can write to.
		Screen screen = Screen.getPrimary();
		Rectangle2D bounds = screen.getVisualBounds();
		System.out.println(bounds);

		primaryStage.setFullScreen(false);

		double fRateDivisor = 2;//124;//2;//22<- 444 HERE HERE HERE DETERMINES FRAME RATE AND RAINBOW MOVEMENT RATE For Rainbow Lights

		FXMLLoader loader = new FXMLLoader(Sonnet.class.getResource("main.fxml"));


		StackPane stackPane[] = new StackPane[(int)(fRateDivisor + 1)];
		stackPane[0] = new StackPane();
		stackPane[0].setPrefSize(1920, 1080);//stackPane.setPrefSize(1920, 1080);//stackPane.setPrefSize(960, 540);

		Dimension dimension = new Dimension( (int)bounds.getWidth(), (int)bounds.getHeight() );
		dimension.width = (int)bounds.getWidth();
		dimension.height = (int)bounds.getHeight() + 40;
		Dimension Dim = dimension;

		//Image image = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");

		Scene scene[] = new Scene[(int)(fRateDivisor + 1)];
		ProgressBar progressBar = new ProgressBar();
		Button goButton = new Button("Go!");
		Label stateLabel = new Label();
		TextField addressBar = new TextField();
		addressBar.setText("http://www.pixies.zone/PixiesTest.html");
		WebView browser = new WebView();
		browser.setPrefSize( bounds.getWidth(), bounds.getHeight() );
		WebEngine webEngine = browser.getEngine();
		webEngine.load("http://www.pixies.zone/PixiesTest.html");
		WritableImage origionalTextPicture = new WritableImage( dimension.width, dimension.height );
		Image origionalBrowserImage;// = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");
		JFileChooser jFileChooser = new JFileChooser();
		String path = "C:\\TestVideo.mp4", text = "Sky.Netarianism";//"C:\\TestImage.png"//"C:\\TestVideo.mp4"//"C:\\TEMP_Sonnet.mp4";
		File selectedFile = new File (path);

		jFileChooser.setSelectedFile(selectedFile);
		int returnValue = jFileChooser.showSaveDialog(null);
		if (returnValue == JFileChooser.APPROVE_OPTION)
		{
			selectedFile = jFileChooser.getSelectedFile();
			System.out.println(selectedFile.getName());
			System.out.println(selectedFile.getPath());
		}
		SequenceEncoder enc = new SequenceEncoder(selectedFile);
		Worker<Void> worker = webEngine.getLoadWorker();
		worker.stateProperty().addListener(new ChangeListener<State>() {
			@Override
			public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
				stateLabel.setText("Loading state: " + newValue.toString());
				if (newValue == Worker.State.SUCCEEDED) {
					primaryStage.setTitle(webEngine.getLocation());
					stateLabel.setText("Finish!");
					WritableImage origionalTextPicture = new WritableImage( dimension.width, dimension.height ), bufferPicure = new WritableImage( dimension.width, dimension.height );
					/*//Image origionalBrowserImage = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");//browser.snapshot(sP, origionalTextPicture);//new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");//
					//Image origionalBrowserImage = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Test.png");//browser.snapshot(sP, origionalTextPicture);//new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");//
					stackPane[0].getChildren().add(browser);

					scene[0] = new Scene(stackPane[0]);
					primaryStage.setScene(scene[0]);

					primaryStage.setFullScreen(true);
					primaryStage.show();

					//boolean encFinished = false;
					//while (encFinished =  false)
						//if ( stateLabel.getText() == "Finish!")//primaryStage.isShowing() && primaryStage.isFullScreen() )
						//{*/
					SnapshotParameters sP = new SnapshotParameters();
					sP.setViewport(bounds);
					stackPane[0].getChildren().add(browser);
					scene[0] = new Scene(stackPane[0]);
					//Image origionalBrowserImage = browser.snapshot(sP, origionalTextPicture);
					Image origionalBrowserImage = scene[0].snapshot(origionalTextPicture);


							//VBox root = new VBox();
							//root.getChildren().addAll(addressBar, goButton, stateLabel, progressBar, browser);
							//scene[0] = new Scene(stackPane[0]);
							//primaryStage.setScene(scene[0]);



							//primaryStage.setFullScreen(true);
							//primaryStage.show();

							//WritableImage origionalTextPicture = new WritableImage( dimension.width, dimension.height );
							//Image origionalBrowserImage = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");//browser.snapshot(sP, origionalTextPicture);//new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");//
							//Image origionalBrowserImage = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Test.png");//browser.snapshot(sP, origionalTextPicture);//new Image("http://www.nanofirm.org/scimagorder.com/Pictures/Pixies%20Text.png");//
							//stackPane[0].getChildren().add(browser);

							//scene[0] = new Scene(stackPane[0]);
							//primaryStage.setScene(scene[0]);

							//primaryStage.setFullScreen(true);
							//primaryStage.show();
							//JUST THIS DISPLAYS BROWSER!!!!!






							//origionalTextPicture = scene[0].snapshot(null);

							//Image origionalBrowserImage = scene[0].snapshot(null);//browser.snapshot(sP, origionalTextPicture);
							//Image origionalBrowserImage = new Image("http://www.nanofirm.org/scimagorder.com/Pictures/FatLevels.png");
							PixelReader origionalpr = origionalBrowserImage.getPixelReader();
							PixelWriter origionalpw = bufferPicure.getPixelWriter();
							ImageView origionalImageView = new ImageView();
							origionalImageView.setImage(origionalBrowserImage);






							//scene[0].setRoot(browser);

							//stackPane[0].getChildren().add(origionalImageView);
							//stackPane[0].getChildren().add(browser);


							/*File tempFile;
				//WebDriver driver=new FirefoxDriver();

				// Maximize the window
				driver.manage().window().maximize();

				// Pass the url
				driver.get("http://www.pixies.zone/PixiesTest.html");

				// Take screenshot and store as a file format
				File src= ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
				try {// now copy the  screenshot to desired location using copyFile //method
					FileUtils.copyFile(src, new File("C:/TempImage.png"));
				}

				catch (IOException e)
				{
					System.out.println(e.getMessage());

				}// */


							WritableImage writableImage = origionalTextPicture;
							PixelReader pr = writableImage.getPixelReader();
							PixelWriter pw = writableImage.getPixelWriter();
							ImageView imageView = new ImageView();
							imageView.setImage(writableImage);

							ColorSlider black = new ColorSlider( new double[]{0,0,0} );

							ColorSlider color = black;

							ColorSlider white = new ColorSlider( new double[]{255,255,255} );
							ColorSlider skyblue = new ColorSlider( new double[]{134,206,249} );
							ColorSlider pink = new ColorSlider( new double[]{255,64,143} );
							ColorSlider blue = new ColorSlider( new double[]{0,0,192} );
							ColorSlider red = new ColorSlider( new double[]{193,0,0} );
							ColorSlider purple = new ColorSlider( new double[]{122,0,178} );
							ColorSlider orange = new ColorSlider( new double[]{255,134,0} );
							ColorSlider green = new ColorSlider( new double[]{0,133,50} );
							ColorSlider yellow = new ColorSlider( new double[]{246,252,15} );
							ColorSlider teal = new ColorSlider( new double[]{3,224,149} );
							ColorSlider bronze = new ColorSlider( new double[]{152,123,46} );
							ColorSlider silver = new ColorSlider( new double[]{193,192,192} );
							ColorSlider gold = new ColorSlider( new double[]{205,191,44} );
							ColorSlider lime = new ColorSlider( new double[]{126,193,33} );
							ColorSlider brown = new ColorSlider( new double[]{131,103,71} );

							int pixiePink = (int)(255 * 16777216) + (int)(255 * 65536) + (int)(0 * 256) + 255;

							int numberOfColorsInTheRainbow = 7;//asdf Always Worry About This!

							Dimension HalfedDim = new Dimension();
							HalfedDim.width = Math.round( ( Dim.width + 1 ) / 2 - 1 );
							HalfedDim.height = Math.round( ( Dim.height + 1 ) / 2 - 1 );
							int x = 0, y = 0, xMinusxSlider = 0, yMinusxSlider = 0, cxMx = 0, ySlider = 0, yMinusySlider = 0, cyMy = 0,  b = 0, xSliderFactor = 1, xSliderBackAndFourth = 1, fixedOfabcd = 4, numOfabcd = 4, colorIntervalDivisor = 1, aCounter = 0, bCounter = 0, cCounter = 0;//cxMx Corrected xMinusSlider for determining color
							double xSlider = 0, a = 0, colorInterval = Dim.width / ( numberOfColorsInTheRainbow - 1 ), numberOfClockHands = 16, abcd = 0, abc = 0, rCheck = 0, aAngle = 0, bAngle = 0, newx = 0, newy = 0, abc2 = 0, aIncrementAngle = 0, bIncrementAngle = 0, aTan = 0;
							boolean TrispectralRainbow = false;
							if (TrispectralRainbow == true)
								colorInterval = colorInterval / 3;//For Trispectral Rainbow.
							double colorDisplacement = 0;//For Rainbow Disk And 0 Rainbow Clock
							double radialDistance = Math.pow(Math.pow(HalfedDim.width + 1, 2) + Math.pow(HalfedDim.height + 1, 2), 0.5);
							double angle1 = 0, angle2 = 0, angle3 = 0, angle4 = 0, aAngleCheck = 0;
							double radius = 0;
							double fullAngle = Math.PI * radialDistance;
							double interval = fullAngle / 2 / fRateDivisor;//Last Division Determines The Frame Rate
							colorInterval = fullAngle / ( numberOfColorsInTheRainbow - 1 );//For Rainbow Clock And Spiral
							///double interval = radialDistance * 2 * Math.PI / 1444;//1444 Instead Of 14 Gets The Frame Rate To Have Contiguous Motion For Rainbow Clock
							//double fullAngle = 2 * Math.PI * radialDistance;//For Rainbow Clock
							//colorInterval = fullAngle / ( numberOfColorsInTheRainbow - 1 ) / numberOfClockHands;//For Rainbow Clock
							//for (xSlider = (int)Math.round(colorDisplacement) + radialDistance * 2 * Math.PI / numberOfClockHands / 2; xSlider < 1.5 * ( radialDistance * 2 * Math.PI / numberOfClockHands ); xSlider++)// < For Rainbow Clock, xSlider = (int)Math.round(colorDisplacement); For Rings -144 Use cy And < HalfedDim.height Instead of Dim.height For Circular Rainbow Use Dim.width < For Rainbow Slider And Fractal //Start At -144 For Videos And Pictures
							while ( xSlider < fullAngle )
							{//0.175979734764 * 
								//Dim = f.getSize();//Dim = f.getContentPane().getSize();
								HalfedDim.width = Math.round( ( Dim.width + 1 ) / 2 - 1 );
								HalfedDim.height = Math.round( ( Dim.height + 1 ) / 2 - 1 );
								radialDistance = Math.pow(Math.pow(HalfedDim.width + 1, 2) + Math.pow(HalfedDim.height + 1, 2), 0.5);
								rCheck = HalfedDim.height / fixedOfabcd;
								numOfabcd = (int)Math.ceil(radialDistance / HalfedDim.height);
								//double[] angle = new double[numOfabcd], abcdefg = new double[numOfabcd];
								double angle = 0;
								colorDisplacement = 0;//For Rainbow Disk
								for (x = 0; x < Dim.width; x++)//Comment Out Here For Circular Rainbow
								{//Comment Out Here For Circular Rainbow
									for (y = 0; y < Dim.height; y++)
									{	
										angle = ( Math.atan2( (x - HalfedDim.width + 1) , (y - HalfedDim.height + 1 ) ) + Math.PI ) * radialDistance + xSlider;//For Rainbow Strobe Effect Use: angle = Math.atan2( (x - HalfedDim.width + 1) , (y - Dim.height * 4 / 3 + 1 ) );// For Rising Sun + 1
										if (angle < 0)
											angle = angle + fullAngle;
										else
											if (angle > fullAngle)
												angle = angle - fullAngle;
										radius = Math.pow( Math.pow( (x - HalfedDim.width + 1) , 2) + Math.pow( (y - HalfedDim.height + 1) , 2) , 0.5);
										aAngle = fullAngle;
										colorIntervalDivisor = 1;
										while ( radius > rCheck )
										{
											aAngle = aAngle / 4;
											colorIntervalDivisor++;
											while (angle > aAngle)
											{
												angle = angle - aAngle;
												radius = radius - rCheck;
											}
											//radius = radius - rCheck;
										}
										abcd = angle;
										while ( abcd < colorDisplacement)//For Rainbow Ring
											abcd = abcd + aAngle - colorDisplacement;//BAD COMMENT: For Rainbow Ring Take Out - 38
										while ( abcd > aAngle )//radius > fullAngle For Non Infinite Number Theorem
											abcd = abcd - aAngle - colorDisplacement; //radius = radius - fullAngle; For Non Infinite Number Theorem //For Rainbow Clock Comment Out To Here. Here -- */
										if ( abcd >= colorDisplacement && abcd < (numberOfColorsInTheRainbow - 1) * colorInterval  + colorDisplacement)//For Purple Outside Ring
										{
											if ( origionalpr.getArgb(x, y) == pixiePink )
												if ( abcd < colorInterval  + colorDisplacement)//For Normal Rainbow Use This Instead Of The Others
													color.ColorSliderFunction(colorInterval, abcd - colorDisplacement, purple, blue);
												else if ( abcd < ( 2 * colorInterval  + colorDisplacement) )
													color.ColorSliderFunction(colorInterval, abcd - colorInterval - colorDisplacement, blue, teal);
												else if ( abcd < ( 3 * colorInterval  + colorDisplacement) )		
													color.ColorSliderFunction(colorInterval, abcd - 2 * colorInterval - colorDisplacement, teal, pink);
												else if ( abcd < ( 4 * colorInterval  + colorDisplacement) )
													color.ColorSliderFunction(colorInterval, abcd - 3 * colorInterval - colorDisplacement, pink, yellow);
												else if ( abcd < ( 5 * colorInterval  + colorDisplacement) )
													color.ColorSliderFunction(colorInterval, abcd - 4 * colorInterval - colorDisplacement, yellow, orange);
												else
													color.ColorSliderFunction(colorInterval, abcd - 5 * colorInterval - colorDisplacement, orange, red);
											else//*/
												if ( abcd < colorInterval  + colorDisplacement)//For Normal Rainbow Use This Instead Of The Others
													color.ColorSliderFunction(colorInterval, abcd - colorDisplacement, red, orange);
												else if ( abcd < ( 2 * colorInterval  + colorDisplacement) )
													color.ColorSliderFunction(colorInterval, abcd - colorInterval - colorDisplacement, orange, yellow);
												else if ( abcd < ( 3 * colorInterval  + colorDisplacement) )		
													color.ColorSliderFunction(colorInterval, abcd - 2 * colorInterval - colorDisplacement, yellow, green);
												else if ( abcd < ( 4 * colorInterval  + colorDisplacement) )
													color.ColorSliderFunction(colorInterval, abcd - 3 * colorInterval - colorDisplacement, green, teal);
												else if ( abcd < ( 5 * colorInterval  + colorDisplacement) )
													color.ColorSliderFunction(colorInterval, abcd - 4 * colorInterval - colorDisplacement, teal, blue);
												else
													color.ColorSliderFunction(colorInterval, abcd - 5 * colorInterval - colorDisplacement, blue, purple);//*
										}
										//Use To //*/ For Rainbow Clock
										/*double angle = ( Math.atan2( (x - HalfedDim.width + 1) , (y - HalfedDim.height + 1 ) ) + Math.PI ) * radialDistance + xSlider;
							if (angle < 0)
								angle = angle + fullAngle / numberOfClockHands;
							else
								while (angle > fullAngle / numberOfClockHands)
									angle = angle - fullAngle / numberOfClockHands;
							//angle = 0;//Testing Purposes Only.
							if ( angle < colorInterval)//For Normal Rainbow Use This Instead Of The Others
								color.ColorSliderFunction(colorInterval, angle, red, orange);
							else if ( angle < 2 * colorInterval )
								color.ColorSliderFunction(colorInterval, angle - colorInterval, orange, yellow);
							else if ( angle < 3 * colorInterval )		
								color.ColorSliderFunction(colorInterval, angle - 2 * colorInterval, yellow, green);
							else if ( angle < 4 * colorInterval )
								color.ColorSliderFunction(colorInterval, angle - 3 * colorInterval, green, teal);
							else if ( angle <  5 * colorInterval )
								color.ColorSliderFunction(colorInterval, angle - 4 * colorInterval, teal, blue);
							else
								color.ColorSliderFunction(colorInterval, angle - 5 * colorInterval, blue, purple);//*/

										pw.setArgb( x, y, (int)(255 * 16777216 + (int)color.RGB[0] * 65536 + (int)color.RGB[1] * 256 + (int)color.RGB[2]));//setArgb
									}
								}
								imageView.setImage(writableImage);

								stackPane[(int)(fRateDivisor * xSlider/fullAngle) + 1] = new StackPane();
								stackPane[(int)(fRateDivisor * xSlider/fullAngle) + 1].getChildren().add(browser);
								stackPane[(int)(fRateDivisor * xSlider/fullAngle) + 1].getChildren().add(imageView);
								scene[(int)(fRateDivisor * xSlider/fullAngle) + 1] = new Scene(stackPane[(int)(fRateDivisor * xSlider/fullAngle) + 1]);
								primaryStage.setScene(scene[(int)(fRateDivisor * xSlider/fullAngle) + 1]);

								System.out.println(Dim);

								primaryStage.setFullScreen(true);

								primaryStage.show();

								if (xSlider == (int)Math.round(colorDisplacement) + radialDistance * 2 * Math.PI / numberOfClockHands / 2)
								{
									File outputFile = new File("C:/TestImage.png");
									BufferedImage bImage = SwingFXUtils.fromFXImage(scene[(int)(fRateDivisor * xSlider/fullAngle) + 1].snapshot(null), null);
									try {
										ImageIO.write(bImage, "png", outputFile);
									} catch (IOException e) {
										throw new RuntimeException(e);
									}
								}
								//enc.encodeImage( SwingFXUtils.fromFXImage(scene[(int)(fRateDivisor * xSlider/fullAngle) + 1].snapshot(null), null ) );
								//enc.encodeImage( SwingFXUtils.fromFXImage( imageView.getImage(), null ) );


								xSlider = xSlider + interval;
								System.out.println(Dim);
								//}
								//Thread.sleep(2000);}
								//catch (Exception ex) {ex.printStackTrace();}

							}
							//enc.finish();
							//encFinished = true;
						//}
					/*webEngine.getLoadWorker().stateProperty().addListener(
					        new ChangeListener<State>() {
					            public void changed(ObservableValue ov, State oldState, State newState) {
					                if (newState == State.SUCCEEDED) {
					                    primaryStage.setTitle(webEngine.getLocation());
					                }
					            }
					        });*/
					/*browser.getEngine().getLoadWorker().stateProperty().addListener(
							  (ObservableValue<? extends worker.State> observable,
							    worker.State oldValue,
							    worker.State newValue) -> {
							    if( newValue != worker.State.SUCCEEDED ) {
							      return;
							    }

							    // Your logic here
							  } );*/

					//if (worker.State.SUCCEEDED == true)
					//{


					//}
					/*scene.setOnKeyReleased(new EventHandler<KeyEvent>()
					{
						@Override
						public void handle(KeyEvent event)
						{
							if ( event.isAltDown() == true)
							{
								switch (event.getCode())
								{
									case ENTER: primaryStage.setFullScreen(!primaryStage.isFullScreen()); break;
								}
							}
						}
					});//*/
					//browser.snapshot(sP, origionalTextPicture);
				} } });


		progressBar.progressProperty().bind(worker.progressProperty());

		goButton.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				String url = addressBar.getText();
				// Load the page.
				webEngine.load(url);
			}
		});
		
	}

	public static void main(String[] args) throws IOException
	{
		launch(args);

	}
}